﻿/// <reference path="TsLinq.d.ts" />
/// <reference path="List.ts" />
/// <reference path="Linq.ts" />
/// <reference path="DefaultComparer.ts" />
/// <reference path="KeyValuePair.ts" />

class Dictionary<TKey, TValue> extends List<IKeyValuePair<TKey, TValue>> implements IDictionary<TKey, TValue> {

    //
    //  Adds a new entry. 
    //
    add(key: TKey, value: TValue = undefined): void {
        if (this.containsKey(key)) {
            throw new Error('Can not add already added key <' + key.toString() + '>');
        }
        super.push(new KeyValuePair<TKey, TValue>(key, value));
    }

    //
    //  Counts all elements. If an expression is given, the system counts all elements which are fitting this expression.
    //
    count(expr?: (item: IKeyValuePair<TKey, TValue>) => boolean): number {
        return super.count(expr);
    }

    //
    //  Returns a value wherever the value list contains the given value.
    //
    containsValue(value: TValue, valueComparer?: IComparer<TValue>): boolean {
        return super.contains(new KeyValuePair<TKey, TValue>(null, value), new KeyValueComparerForValue<TKey, TValue>(valueComparer));
    }

    //
    //  Returns whenever the key was added to the collection. Optionally you can add a comparer to find the correct key.
    // 
    containsKey(key: TKey, keyComparer?: IComparer<TKey>): boolean {
        return super.contains(new KeyValuePair(key, null), new KeyValueComparerForKey<TKey, TValue>(keyComparer));
    }

    //  
    //  Clears all items in the dictionary.
    //
    clear(): void {
        super.clear();
    }

    //
    //  Removes the entry with the specified key.
    //
    removeKey(key: TKey, comp?: IComparer<TKey>): TValue {
        var index = this.indexOf(new KeyValuePair(key, null), new KeyValueComparerForKey<TKey, TValue>(comp));
        if (index > -1) {
            var value = this.tryGetValue(key, comp);
            this._items.splice(index, 1);
            return value;
        }
        throw new Error('Key <' + key.toString() + '> was not found for removing');
    }

    //
    //  tries returning a value with a specific key. If the value does not exists, the method returns null.
    //
    tryGetValue(key: TKey, comp?: IComparer<TKey>): TValue {
        var comparer = comp || new DefaultComparer();
        var foundValue: TValue = null;
        this.forEach(kvp => {
            if (comparer.compare(key, kvp.key) == 0) {
                foundValue = kvp.value;
                return false;
            }
        });
        return foundValue;
    }

    //
    //  Returns the first element index of the entry with the matching key.
    //
    indexOfKey(key: TKey, comp?: IComparer<TKey>): number {
        return super.indexOf(new KeyValuePair(key, null), new KeyValueComparerForKey<TKey, TValue>(comp || new DefaultComparer<TKey>()));
    }

    //
    //  Returns the value of the given key. If a comparer is specified, it will used to compare the keys.
    //
    get(key: TKey, comp?: IComparer<TKey>): TValue {
        var index = this.indexOfKey(key, comp);
        if (index < 0) {
            if (console && console.log) {
                console.log(key);
            }
            throw new Error('Key <' + key + '> was not found. Look into console in chrome for more infos.');
        }
        return this.elementAt(index).value;
    }

    //  
    //  Returns an array of all keys.
    //
    getKeys(): TKey[] {
        return this.select(kvp => kvp.key).toArray();
    }

    //
    //  Returns an array of all values in the dictionary.
    //
    getValues(): TValue[] {
        return this.select(kvp => kvp.value).toArray();
    }
} 